using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace HB.CacheDb
{
    /// <summary>
    /// 数据库中间件
    /// </summary>
    public class CacheDb
    {
        ICacheDbCallBack CallBack { get; set; }
        /// <summary>
        /// 配置持久化，若为空，则为内存数据库
        /// </summary>
        /// <param name="callBack"></param>
        public CacheDb(ICacheDbCallBack callBack)
        {
            this.CallBack = callBack;
        }
        Dictionary<string, CollectionItem> DB = new Dictionary<string, CollectionItem>();
        CollectionItem CreatTableIfNoExist<T>(dynamic getKey)
        {
            string tableName = typeof(T).ToString();
            if (!DB.ContainsKey(tableName))
            {
                DB[tableName] = new CollectionItem()
                {
                    Dic = new ConcurrentDictionary<object, dynamic>(),
                    getKey = getKey
                };
                if (getKey == null)
                {
                    throw new Exception("必须提供主键计算函数");
                }
            }
            return DB[tableName];
        }
        /// <summary>
        /// 初始化内存数据
        /// </summary>
        /// <typeparam name="T">类</typeparam>
        /// <param name="datas">T的集合,可以为null</param>
        /// <param name="getKey">返回T的主键，主键如果重复，将保留最后的数据</param>
        /// <param name="forceOnly">强制key唯一，若发现重复，将抛出异常</param>
        /// <param name="UseDeepCopy">返回对象是否使用深度拷贝，否则为引用模式</param>
        /// <param name="DeepCopyFunc">自行实现的深拷贝算法，直接属性赋值最为高效，不传则使用动态编译Func<T,T>，初始化可能需要几秒，后续与编译代码效率无差异</param>
        public void InitializeTable<T>(List<T> datas, Func<T, object> getKey, bool forceOnly = true, bool UseDeepCopy = false, Func<T, T> DeepCopyFunc = null)
        {
            var collection = CreatTableIfNoExist<T>(getKey);
            collection.UseDeepCopy = UseDeepCopy;
            collection.deepCopyFunc = UseDeepCopy ? (DeepCopyFunc ?? QueryExpand.CompileDeepCopy<T>()) : null;
            if (datas == null) { return; }
            foreach (var data in datas)
            {
                if (getKey == null)//如果没有主键，采用系统guid
                {
                    throw new Exception("主键缺失");
                }
                else
                {
                    if (forceOnly)
                    {
                        if (!collection.Dic.TryAdd(getKey(data), data))
                        {
                            throw new Exception("主键重复");
                        }
                    }
                    else
                    {
                        collection.Dic[getKey.Invoke(data)] = data;
                    }
                }
            }
        }

        /// <summary>
        /// 获取数据查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="timeout">高并发内存锁等待时间</param>
        /// <returns></returns>
        public Query<T> Table<T>(int timeout = 5000) where T : class, new()
        {
            string tableName = typeof(T).ToString();
            if (DB.ContainsKey(tableName))
            {

                return new Query<T>(DB[tableName], CallBack, timeout);
            }
            else
            {
                throw new Exception($"未能找到Table：{tableName }，请先初始化该表");
            }
        }
    }
}
